﻿import com.audiopackage.*;
import com.gamepackage.events.*;
import com.gamepackage.tilemap.*;
import com.gamepackage.tilemap.layer.*;

class Mario extends Sprite
{
	//-- PHYSIC PROPERTIES --//
	private var HORIZONTAL_ACCELERATION: Number = .25;
	private var MAX_HORIZONTAL_VELOCITY: Number = 4.0;
	private var HORIZONTAL_DECAY: Number 		= .94;
	private var JUMP_FORCE: Number 				=  10.5;
	private var GRAVITY: Number 				= .75;
	
	//-- PHYSICS RUNTIME --//
	private var vx: Number;
	private var vy: Number;
	private var rooted: Boolean;
	
	//-- BODY PROPERTIES --//
	private var width: Number;
	private var height: Number;
	
	//-- SOUND --//
	private var s_coin: GSound;
	
	//-- INTERACT BYTE MAP --//
	private var map: Array;
	
	//-- MARIOS LAYER --//
	private var layer: TileLayer;

	//-- ANIMATION --//
	private var frame: Number;
	
	//-- CONTROLS --//
	private var KeyUP: Boolean;
	
	function Mario( layer: TileLayer, width: Number, height: Number, map: Array )
	{
		super( layer );
		
		this.width 	= width;
		this.height = height;
		this.map 	= map;
		
		this.layer	= layer;
		
		vx = vy = 0;
		
		frame = 0;
		
		rooted 	= false;
		KeyUP	= false;
		
		new Thread( this , run ).start();
	}
	
	function initSound( Void ): Void
	{
		var group: GSoundGroup = GSoundGroup.getInstanceByName( 'common' );
		
		s_coin = group.getNewGSound( 's_coin' );
	}
	
	function run( Void ): Void
	{
		if ( Key.isDown( 37 ) )
		{
			if ( vx >-MAX_HORIZONTAL_VELOCITY ) vx -= HORIZONTAL_ACCELERATION;
		}
		else if ( Key.isDown( 39 ) )
		{
			if ( vx < MAX_HORIZONTAL_VELOCITY ) vx += HORIZONTAL_ACCELERATION;
		}
		else
		{
			vx *= HORIZONTAL_DECAY;
		}
		
		if ( Key.isDown( 38 ) )
		{
			if ( rooted && !KeyUP )
			{
				vy = -JUMP_FORCE;
				KeyUP = true;
			}
		}
		else KeyUP = false;
		
		//-- PHYSICS
		vy += GRAVITY;
		
		limitSpeed();
		
		reactPhysicBytes();
		reactLayerItems();
		
		//-- ANIMATION
		controlTimeline();
		
		super.moveTo( x , y );
	}
	
	private function reactLayerItems( Void ): Void
	{
		var items = layer.getMap();
		var tx = x >> 4;
		var ty = ( y - height / 2 ) >> 4;
		if( items[ty][tx] == 1 )
		{
			layer.removeTile( tx , ty );
			s_coin.start( 0 , 1 );
		}
	}
	
	private function reactPhysicBytes( Void ): Void
	{
		//-- DETECT 2 POINTS FOR THE BODY (LEFT & RIGHT BOUNDINGS) --//
		var w: Number = width / 2;
		var x0 = x + w;
		
		var tx0: Number = x0 >> 4;
		var tx1: Number = ( x - w ) >> 4;
		
		//-- VERTICAL MOVEMENT --//
		//
		if ( vy > 0 )
		{
			var ry: Number = ( y + vy ) >> 4;
			
			var row: Array = map[ry];
			
			var byte0: Number = row[tx0-(x0 % 16 == 0)];
			var byte1: Number = row[tx1];
			
			if( ( byte0 | byte1 ) & 1 )
			{
				//-- ALLREADY FLOOR CONTACT
				if ( y % 16 == 0 )
				{
					//-- RESET VERTICAL FORCES
					vy = 0;
				}
				//-- MOVEMENT INTERSECTS TILE UPPERLINE
				else if ( ( y >> 4 ) < ry )
				{
					//-- PLACE HARDLY ON TILE
					y = ry << 4;
					
					//-- SIMPLE SPRING MODEL
					vy *= -.2;
					
					rooted = true;
				}
				else
				{
					y += vy;
					rooted = false;
				}
			}
			else
			{
				y += vy;
				rooted = false;
			}
		}
		else // if ( vy < 0 )
		{
			var ry: Number = ( y - height + vy ) >> 4;
			
			var row: Array = map[ry];
			
			var byte0: Number = row[tx0-(x0 % 16 == 0)];
			var byte1: Number = row[tx1];
			
			if( ( byte0 | byte1 ) & 4 )
			{
				//-- BOUNCE
				vy *= -.5;
			}
			else
			{
				y += vy;
				rooted = false;
			}
		}
		
		//-- HORIZONTAL MOVEMENT --//
		//
		if ( vx > 0 )
		{
			var ty0: Number = ( y - height ) >> 4;
			var ty1: Number = y >> 4;
			var rx: Number = ( x + w + vx ) >> 4;
			
			var byte0: Number = map[ty0][rx];
			var byte1: Number = map[ty1-rooted][rx];
			
			if( ( byte0 | byte1 ) & 2 )
			{
				if ( vx > 0 )
				{
					x = ( rx << 4 ) - w;
					vx = 0;
				}
				else if ( vx < 0 )
				{
					x = (( rx + 1 ) << 4 ) + w;
					vx = 0;
				}
			}
			else
			{
				x += vx;	
			}
		}
		else if ( vx < 0 )
		{
			var ty0: Number = ( y - height ) >> 4;
			var ty1: Number = y >> 4;
			var rx: Number = ( x - w + vx ) >> 4;
			
			var byte0: Number = map[ty0][rx];
			var byte1: Number = map[ty1-rooted][rx];
			
			if( ( byte0 | byte1 ) & 2 )
			{
				if ( vx > 0 )
				{
					x = ( rx << 4 ) - w;
					vx = 0;
				}
				else if ( vx < 0 )
				{
					x = (( rx + 1 ) << 4 ) + w;
					vx = 0;	
				}
			}
			else
			{
				x += vx;	
			}
		}// else no more calculations needed...
	}
	
	private function limitSpeed( Void ): Void
	{
		if ( vx > 16 ) vx = 16
		else if ( vx < -16 ) vx -16;
		
		if ( vy > 16 ) vy = 16
		else if ( vy < -16 ) vy -16;
	}
	
	private function controlTimeline( Void ): Void
	{
		timeline.gotoAndStop( 2 - rooted );
		
		if ( Math.abs( vx ) < HORIZONTAL_ACCELERATION )	//-- #MARIO SLOWER THAN ACCELERATION > HARD STOP
		{
			vx = 0;
			timeline.phase.gotoAndStop( 1 );
		}
		else
		{
			//-- DYNAMIC GOTOANDSTOP WALKING FRAMES --//
			//-- #SQRT IS SMOOTHER
			//
			frame += Math.sqrt( Math.abs( vx ) / MAX_HORIZONTAL_VELOCITY );
			
			timeline.phase.gotoAndStop( int( frame % timeline.phase._totalframes ) + 1 );
		}
		
		//-- MOVIECLIP TRANSFORMATION --//
		if ( vx > 0 )
		{
			timeline._xscale = 100;
		}
		else if ( vx < 0 )
		{
			timeline._xscale = -100;
		}
	}
}